<template>
  <div class="page">
    <div class="top">
      <input v-model="uri" :disabled="connected">
      <button @click="onConnect" :disabled="connected">{{ connected ? '已连接' : '连接' }}</button>
      <button v-show="connected" @click="onDeConnect">断开</button>
    </div>

    <div class="content">
      <div class="left">
        <div class="row" v-for="(obj, i) in sendCMDList" :key="i">
          <div class="row-operator">
            <input :disabled="!connected" class="cmd" v-model="obj.cmd">
            <button :disabled="!connected" @click="onSend(obj)">发送</button>
          </div>
          <textarea v-model="obj.content"></textarea>
        </div>
      </div>

      <div class="right">
        <div class="add-wrap">
          <input :disabled="!connected" class="cmd" v-model="inputedListenCMD">
          <button :disabled="!connected" @click="onAddListener">添加监听</button>
        </div>
        <div class="tabs">
          <MessageBox class="listen-item" v-for="(item, i) in listenList" :key="i"
                      :name="item.cmd" :message-list="item.massageList"
                      @delete="onDeleteListener"></MessageBox>
        </div>
      </div>
    </div>


    <MessageBox class="bottom" :has-header="false" :message-list="messageList"></MessageBox>

  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';
import { Socket } from "vue-socket.io-extended";
import MessageBox from "@/components/MessageBox.vue";
import {SendObj, ListenerObj} from "@/components/Model";
import LocalStore from "@/utils/LocalStore";

@Component({
  components: {MessageBox}
})
export default class HelloWorld extends Vue {
  @Prop() private msg!: string;
  private timeout: any | null = null;

  private uri: string = '127.0.0.1:5000'
  private connected = false
  private inputedListenCMD: string | null = null

  private messageList: string[] = []
  private sendCMDList: SendObj[] = []
  private listenList: ListenerObj[] = []

  beforeDestroy() {
    console.log('==> beforeDestroy')
  }

  created() {
    this.connected = this.$socket.connected
    this.messageList = ['hello websocket of socket.io ["socket.io-client": "^2.4"]']

    this.loadStoreData()

    for (let i = 0; i < 5 - this.sendCMDList.length; i++) {
      this.sendCMDList.push({cmd: null, content: ''})
    }
  }

  /** event */

  onConnect() {
    this.connectSocket()
  }

  onDeConnect() {
    this.$socket.client.disconnect()
  }

  onSend(obj: SendObj) {
    console.log(obj)
    if (obj.cmd && obj.cmd.trim() != '') {

      if (obj.content && obj.content.trim() != '') {
        const content = obj.content.trim()
        this.$socket.client.emit(obj.cmd, content)
        this.messageList.push(`==>send cmd: ${obj.cmd}  content: ${content}`)
      }else {
        this.$socket.client.emit(obj.cmd)
        this.messageList.push(`==>send cmd: ${obj.cmd}`)
      }
    }
    this.saveSendCMDList()
  }

  onAddListener() {
    if (this.listenList.length >= 3) { return }

    if (this.inputedListenCMD && this.inputedListenCMD.trim() != '') {
      const cmd = this.inputedListenCMD
      const index = this.hasSameListener(cmd)
      if (index != null) {
        this.messageList.push(`==>Error: 已存在相同的监听${cmd}`)
        return
      }

      const listener: ListenerObj = {cmd: this.inputedListenCMD, massageList: []}
      this.listenList.push(listener)
      this.addAListenerHandle(listener)
    }

    this.saveListenCMDList()
  }

  onDeleteListener(cmd: string) {
    const index = this.hasSameListener(cmd)
    if (index != null) {
      this.$socket.client.removeEventListener(cmd)
      this.messageList.push(`==>remove listener: ${cmd}`)
      this.listenList.splice(index )
    }

    this.saveListenCMDList()
  }

  /** socket */

  connectSocket() {
    this.$socket.client.io.uri = 'http://' + this.uri
    this.$socket.client.io.opts.transports = ['websocket', 'polling']

    this.messageList.push(`==>开始连接 ${this.$socket.client.io.uri}`)

    this.$socket.client.open();

    this.timeout = setTimeout(() => {
      clearTimeout(this.timeout!)
      if (this.$socket.connected == false) {
        console.log("==> Socket连接超时");
      }
    }, 10000);
  }

  @Socket()
  connect() {
    this.connected = true
    this.messageList.push(`==>Socket连接成功 ${this.$socket.client.io.uri}`)

    this.saveURL()

    this.addListenFromLocalStore()
  }
  @Socket()
  disconnect() {
    this.connected = false
    this.messageList.push(`==>Socket断开连接 ${this.$socket.client.io.uri}`)
  }

  /** localStore */

  addListenFromLocalStore() {
    this.listenList.forEach((listener) => {
      this.addAListenerHandle(listener)
    })
  }

  saveURL() {
    LocalStore.saveSocketURL(this.uri)
  }

  saveSendCMDList() {
    const sendCMDList = this.sendCMDList.filter((e)=> e.cmd != null).map((e)=> e.cmd) as string[]
    if (sendCMDList.length > 0) {
      LocalStore.saveSocketSendCMDList(sendCMDList)
    }
  }

  saveListenCMDList() {
    const listenCMDList = this.listenList.filter((e)=> e.cmd != null).map((e)=> e.cmd) as string[]
    if (listenCMDList.length > 0) {
      LocalStore.saveSocketListenCMDList(listenCMDList)
    }
  }

  loadStoreData() {
    const url = LocalStore.getSocketURL()
    if (url && url.trim() != '') {
      this.uri = url
    }
    const sendCMDList = LocalStore.getSocketSendCMDList()
    if (sendCMDList.length > 0) {
      this.sendCMDList = sendCMDList.map((e) => { return {cmd: e, content: ''} as SendObj })
    }
    const listenCMDList = LocalStore.getSocketListenCMDList()
    if (listenCMDList.length > 0) {
      this.listenList = listenCMDList.map((e) => { return {cmd: e, massageList: []} as ListenerObj })
    }
  }

  /** private */

  hasSameListener(cmd: string): number | null {
    let index: number | null = null
    for (let i = 0; i < this.listenList.length; i++) {
      if (this.listenList[i].cmd == cmd) {
        index = i
        break
      }
    }
    return index
  }

  addAListenerHandle(listener: ListenerObj) {
    const cmd = listener.cmd
    if (this.$socket.client.hasListeners(cmd) == false) {
      this.messageList.push(`==>add listener: ${cmd}`)
      this.$socket.client.addEventListener(cmd, (payload: any) => {
        listener.massageList.push(payload as string)
      })
    }
  }

}
</script>

<style scoped>

.page {
  height: 100%;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 30px;
}


/*top*/
.top {
  display: flex;
  flex-direction: row;
  justify-content: center;
  padding: 20px 0;
}
.top > input {
  width: 300px;
  font-size: 18px;
}
.top > button {
  min-width: 80px;
  min-height: 35px;
  margin-left: 10px;
  font-size: 18px;
}

/*content*/
.content {
  flex: 1;
  overflow: hidden;
  display: flex;
  flex-direction: row;
}

/*left*/
.left {
  overflow: auto;
  max-width: 300px;
  min-width: 250px;
  flex: 1;
  border: 1px solid black;
  padding: 10px;
}
.left input {
  min-width: 150px;
  height: 30px;
  flex: 1;
}
.left button {
  min-width: 60px;
  min-height: 30px;
  margin-left: 8px;
}
.row {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
}
.row:first-child {
  margin: 0;
}
.row-operator {
  display: flex;
  flex-direction: row;
}
textarea {
  margin-top: 5px;
  height: 40px;
}

.right {
  flex: 2;
  border: 1px solid black;
  padding: 10px;
  margin-left: 20px;
  display: flex;
  flex-direction: column;
}
.right input {
  min-width: 150px;
  width: 200px;
  height: 30px;
}
.right  button {
  min-width: 60px;
  min-height: 30px;
  margin-left: 8px;
}
.right .tabs {
  flex: 1;
  display: flex;
  flex-direction: row;
  margin-top: 10px;
}
.right .tabs .listen-item {
  flex: 1;
}


/*bottom*/
.bottom {
  height: 200px;
  max-height: 200px;
  margin-top: 10px;
  overflow: auto;
  border: 1px solid black;
}
</style>
